home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Mac Game Programming Gurus / TricksOfTheMacGameProgrammingGurus.iso / More Source / C⁄C++ / Chess++ 3.0.1 / source / CChessBoard.cp < prev    next >
Text File  |  1993-05-26  |  12KB  |  453 lines

  1. ////////////
  2. //
  3. //    CChessBoard.cp
  4. //
  5. //    Methods for implementing a chess board.
  6. //
  7. //  Copyright © 1993 Steven J. Bushell. All rights reserved.
  8. //
  9. ////////////
  10.  
  11. #include <CBartender.h>
  12. #include <CWindow.h>
  13. #include <string.h>
  14. #include <oops.h>
  15. #include <global.h>
  16. #include "CChessDoc.h"
  17. #include "CChessBoard.h"
  18. #include "CPawn.h"
  19. #include "CKnight.h"
  20. #include "CBishop.h"
  21. #include "CRook.h"
  22. #include "CQueen.h"
  23. #include "CKing.h"
  24. #include "CBrain.h"
  25. #include "ChessCommands.h"
  26.  
  27. Rect    gRectToInvert;
  28.  
  29. extern    CBureaucrat *gGopher;
  30. extern    CChessBoard    *gChessBoard;
  31. extern    CBrain        *gBrain;
  32. extern    CBartender    *gBartender;
  33. extern    RgnHandle    gUtilRgn;
  34. extern    RgnHandle    gChessBoardRgnHandle;
  35. extern    Cursor        gChessCursor,gScopeCursor;
  36. extern    CursHandle    gWatchCursor;
  37.  
  38. void CChessBoard::IChessBoard(CChessPane *theChessPane)
  39. {
  40.     register rank,file;
  41.  
  42.     itsChessPane = theChessPane;
  43.     gameOver = false;
  44.     awaitingFirstClick = true;
  45.     myColor = White;
  46.     theOtherPlayersColor = Black;
  47.  
  48.     for (rank=1;rank<=8;rank++)
  49.         for(file=1;file<=8;file++)
  50.         theBoard[rank][file] = (CChessPiece *)0l;
  51.         
  52.     for (rank=1;rank<=8;rank++)
  53.     {
  54.         theBoard[rank][2] = new CPawn;
  55.             ((CPawn *)theBoard[rank][2])->IPawn(Black);
  56.         theBoard[rank][7] = new CPawn;
  57.             ((CPawn *)theBoard[rank][7])->IPawn(White);
  58.     }
  59.  
  60.     theBoard[1][1] = new CRook;
  61.     ((CRook *)theBoard[1][1])->IRook(Black);
  62.     theBoard[8][1] = new CRook;
  63.     ((CRook *)theBoard[8][1])->IRook(Black);
  64.     theBoard[1][8] = new CRook;
  65.     ((CRook *)theBoard[1][8])->IRook(White);
  66.     theBoard[8][8] = new CRook;
  67.     ((CRook *)theBoard[8][8])->IRook(White);
  68.  
  69.     theBoard[2][1] = new CKnight;
  70.     ((CKnight *)theBoard[2][1])->IKnight(Black);
  71.     theBoard[7][1] = new CKnight;
  72.     ((CKnight *)theBoard[7][1])->IKnight(Black);
  73.     theBoard[2][8] = new CKnight;
  74.     ((CKnight *)theBoard[2][8])->IKnight(White);
  75.     theBoard[7][8] = new CKnight;
  76.     ((CKnight *)theBoard[7][8])->IKnight(White);
  77.  
  78.     theBoard[3][1] = new CBishop;    
  79.     ((CBishop *)theBoard[3][1])->IBishop(Black);
  80.     theBoard[6][1] = new CBishop;
  81.     ((CBishop *)theBoard[6][1])->IBishop(Black);
  82.     theBoard[3][8] = new CBishop;
  83.     ((CBishop *)theBoard[3][8])->IBishop(White);
  84.     theBoard[6][8] = new CBishop;
  85.     ((CBishop *)theBoard[6][8])->IBishop(White);
  86.  
  87.  
  88.     theBoard[4][1] = new CQueen;
  89.     ((CQueen *)theBoard[4][1])->IQueen(Black);
  90.     theBoard[4][8] = new CQueen;
  91.     ((CQueen *)theBoard[4][8])->IQueen(White);
  92.     theBoard[5][1] = new CKing;
  93.     ((CKing *)theBoard[5][1])->IKing(Black);
  94.     RegisterKingLocation(Black,5,1);
  95.     theBoard[5][8] = new CKing;
  96.     ((CKing *)theBoard[5][8])->IKing(White);
  97.     RegisterKingLocation(White,5,8);
  98. }
  99.  
  100.  
  101. /***
  102.  * DoClick
  103.  *
  104.  *    The mouse went down in the pane.
  105.  *    In this method you do whatever is appropriate for your
  106.  *    application. HitPt is given in frame coordinates. The other
  107.  *    parameters, modiferKeys and when, are taken from the event
  108.  *    record.
  109.  *
  110.  *    If you want to implement mouse tracking, this is the method
  111.  *    to do it in. You need to create a subclass of CMouseTask and
  112.  *    pass it in a TrackMouse() message to the pane.
  113.  *
  114.  ***/ 
  115.  
  116. void CChessBoard::DoClick(Point hitPt, short modifierKeys, long when)
  117.  
  118. {
  119.     register rank = (hitPt.h >> 5) + 1, file = (hitPt.v >> 5) + 1;
  120.     short    theColor;
  121.     
  122.     if (gameOver)
  123.     {
  124.         SysBeep(0);
  125.         return;
  126.     }
  127.     
  128.     if (theBoard[rank][file])
  129.         theColor = theBoard[rank][file]->itsColor;
  130.     else
  131.         theColor = NoColor;
  132.  
  133.     if (awaitingFirstClick)  // first click to select piece to move
  134.     {
  135.         if (theColor == myColor) // make sure it's one of ours
  136.         {
  137. doFirst:
  138.             firstClickRank = rank; // save its location
  139.             firstClickFile = file;
  140.             itsChessPane->ShowSelectedSquare();
  141.             awaitingFirstClick = false;  // now we're awaiting the second click
  142.             gBartender->DisableCmd(cmdSwapPlayers);
  143.             if (StillDown())
  144.             {
  145.                 Rect    chessLimitRect,chessSlopRect;
  146.                 CIconHandle CicnHandle;
  147.                 long    deltaPt;
  148.                 
  149.                 itsChessPane->Prepare();
  150.                 if (modifierKeys & optionKey)
  151.                 {
  152.                     ShowPossibleMoves();
  153.                     awaitingFirstClick = true;
  154.                     itsChessPane->ShowSelectedSquare();
  155.                     gBartender->EnableCmd(cmdSwapPlayers);
  156.                     return;
  157.                 }
  158.                 SetRect(&chessLimitRect,0,0,256,256);
  159.                 SetRect(&chessSlopRect,0,0,256,256);
  160.                 CicnHandle = theBoard[rank][file]->GetCicnHandle();
  161.                 BitMapToRegion(gUtilRgn,&(*CicnHandle)->iconMask);
  162.                 OffsetRgn(gUtilRgn,(rank-1) << 5,(file-1) << 5);
  163.                 SetRect(&gRectToInvert,0,0,0,0);
  164.                 deltaPt = DragGrayRgn(gUtilRgn,hitPt,&chessLimitRect,&chessSlopRect,0,&TrackPiece);
  165.                 InvertRect(&gRectToInvert);
  166.                 if (deltaPt == 0x80008000)
  167.                 {
  168.                     // move aborted by dragging off chess board
  169.                     awaitingFirstClick = true;
  170.                     itsChessPane->ShowSelectedSquare();
  171.                     gBartender->EnableCmd(cmdSwapPlayers);
  172.                     return;
  173.                 }
  174.                 else
  175.                 {
  176.                     rank = ((hitPt.h + LoShort(deltaPt)) >> 5) + 1;
  177.                     file = ((hitPt.v + HiShort(deltaPt)) >> 5) + 1;
  178.                     if ((rank != firstClickRank) || (file != firstClickFile))
  179.                     {
  180.                         theColor = theBoard[rank][file] ? theBoard[rank][file]->itsColor : NoColor;
  181.                         if ((theColor != myColor) &&
  182.                             (theBoard[firstClickRank][firstClickFile]->
  183.                             IsValidMove(this,rank,file)))
  184.                         {
  185.                             if (CheckForCheck(rank,file))
  186.                             {
  187.                                 InitCursor();
  188.                                 NoteAlert(CheckNoteAlert,0);
  189.                             }
  190.                             else
  191.                             {
  192.                                 RegisterMove(rank,file);
  193.                                 itsChessPane->ShowMove(rank,file);
  194.                                 awaitingFirstClick = true;
  195.                                 gBartender->EnableCmd(cmdSwapPlayers);
  196.                                 gBrain->isBrainsMove = true;
  197.                                 ((CDocument *)itsChessPane->itsSupervisor)->dirty = true;
  198.                                 gBrain->BecomeGopher(true);
  199.                             }
  200.                         }
  201.                     }
  202.                     else
  203.                         ;
  204.                 }
  205.             }
  206.         }
  207.     }
  208.     else // second click to select square to move to, and/or piece to capture
  209.     {
  210.         if ((rank == firstClickRank) && (file == firstClickFile))
  211.         {
  212.             // same square -- reset selection
  213.             awaitingFirstClick = true;
  214.             itsChessPane->ShowSelectedSquare();
  215.             gBartender->EnableCmd(cmdSwapPlayers);
  216.             goto doFirst;
  217.             return;
  218.         }
  219.         if ((theColor != myColor) &&
  220.             (theBoard[firstClickRank][firstClickFile]->
  221.             IsValidMove(this,rank,file)))
  222.         {
  223.             if (CheckForCheck(rank,file))
  224.             {
  225.                 InitCursor();
  226.                 NoteAlert(CheckNoteAlert,0);
  227.             }
  228.             else
  229.             {
  230.                 RegisterMove(rank,file);
  231.                 itsChessPane->ShowMove(rank,file);
  232.                 awaitingFirstClick = true;
  233.                 gBartender->EnableCmd(cmdSwapPlayers);
  234.                 gBrain->isBrainsMove = true;
  235.                 ((CDocument *)itsChessPane->itsSupervisor)->dirty = true;
  236.                 gBrain->BecomeGopher(true);
  237.             }
  238.         }
  239.         if ((theColor == myColor) &&
  240.             ((rank != firstClickRank) || (file != firstClickFile)))
  241.         {
  242.             itsChessPane->DrawSelectedSquare();
  243.          goto doFirst;
  244.         }
  245.     }
  246. }
  247.  
  248.  
  249. void CChessBoard::ShowPossibleMoves(void)
  250. {
  251.     register possibleRank,possibleFile,theColor;
  252.     Rect aRect;
  253.  
  254.     for(possibleFile=1;possibleFile<9;possibleFile++)
  255.         for(possibleRank=1;possibleRank<9;possibleRank++)
  256.             if (theBoard[firstClickRank][firstClickFile])
  257.                 if ((possibleFile != firstClickFile) || (possibleRank != firstClickRank)) {
  258.                     theColor = theBoard[possibleRank][possibleFile] ?
  259.                                     theBoard[possibleRank][possibleFile]->itsColor :
  260.                                     NoColor;
  261.                     if ((theColor != myColor) &&
  262.                         (theBoard[firstClickRank][firstClickFile]->
  263.                         IsValidMove(this,possibleRank,possibleFile)))
  264.                     {
  265.                         SetRect(&aRect,(possibleRank-1) << 5, (possibleFile-1) << 5,
  266.                                 possibleRank << 5, possibleFile << 5);
  267.                                 
  268.                         InvertRect(&aRect);
  269.                     }
  270.                 }
  271.  
  272.     while(StillDown())
  273.         ;
  274.  
  275.     for(possibleFile=1;possibleFile<9;possibleFile++)
  276.         for(possibleRank=1;possibleRank<9;possibleRank++)
  277.             if (theBoard[firstClickRank][firstClickFile])
  278.                 if ((possibleFile != firstClickFile) || (possibleRank != firstClickRank)) {
  279.                     theColor = theBoard[possibleRank][possibleFile] ?
  280.                                     theBoard[possibleRank][possibleFile]->itsColor :
  281.                                     NoColor;
  282.                     if ((theColor != myColor) &&
  283.                         (theBoard[firstClickRank][firstClickFile]->
  284.                         IsValidMove(this,possibleRank,possibleFile)))
  285.                     {
  286.                         SetRect(&aRect,(possibleRank-1) << 5, (possibleFile-1) << 5,
  287.                                 possibleRank << 5, possibleFile << 5);
  288.                                 
  289.                         InvertRect(&aRect);
  290.                     }
  291.                 }
  292. }
  293.  
  294.  
  295. void CChessBoard::RegisterMove(short rank, short file)
  296. {
  297.     CChessPiece *aPiece = theBoard[rank][file],
  298.                 *myPiece = theBoard[firstClickRank][firstClickFile];
  299.     theBoard[rank][file] = myPiece;
  300.     theBoard[firstClickRank][firstClickFile] = (CChessPiece *)0L;
  301.     
  302.     if (myPiece->itsValue == kKingValue)
  303.         RegisterKingLocation(myPiece->itsColor,rank,file);
  304.     
  305.     lastFirstClickRank = firstClickRank;
  306.     lastFirstClickFile = firstClickFile;
  307.     lastSecondClickRank = rank;
  308.     lastSecondClickFile = file;
  309. }
  310.  
  311.  
  312. void CChessBoard::RegisterKingLocation(short theColor, short rank, short file)
  313. {
  314.     if (theColor == White)
  315.     {
  316.         whiteKingRank = rank;
  317.         whiteKingFile = file;
  318.     }
  319.     else
  320.     {
  321.         blackKingRank = rank;
  322.         blackKingFile = file;
  323.     }
  324. }
  325.  
  326.  
  327. pascal void TrackPiece(void)
  328. {
  329.     Point    thePt;
  330.     register rank,file;
  331.     short    pieceColor=NoColor,thisFirstClickRank,thisFirstClickFile;
  332.     static short    oldHiliteRank,oldHiliteFile;
  333.  
  334.     GetMouse(&thePt);
  335.     rank = (thePt.h >> 5) + 1;
  336.     file = (thePt.v >> 5) + 1;
  337.     
  338.     if ((rank<1) || (file<1))    // escape if we're off the board while tracking
  339.     {
  340.         SetCursor(&arrow);
  341.         InvertRect(&gRectToInvert);
  342.         SetRect(&gRectToInvert,0,0,0,0);
  343.         return;
  344.     }
  345.  
  346.     if ((rank>8) || (file>8))
  347.     {
  348.         SetCursor(&arrow);
  349.         InvertRect(&gRectToInvert);
  350.         SetRect(&gRectToInvert,0,0,0,0);
  351.         return;
  352.     }
  353.     
  354.     if (EmptyRect(&gRectToInvert))
  355.     {
  356.         oldHiliteRank = 0;
  357.         oldHiliteFile = 0;
  358.     }
  359.     
  360.     if (gChessBoard->theBoard[rank][file])
  361.         pieceColor = gChessBoard->theBoard[rank][file]->itsColor;
  362.     
  363.     thisFirstClickRank = gChessBoard->firstClickRank;
  364.     thisFirstClickFile = gChessBoard->firstClickFile;
  365.     if ((pieceColor != gChessBoard->myColor) &&
  366.         (gChessBoard->theBoard[thisFirstClickRank][thisFirstClickFile]->
  367.         IsValidMove(gChessBoard,rank,file)))
  368.     {
  369.         SetCursor(&gScopeCursor);
  370.         if ((oldHiliteRank != rank) || (oldHiliteFile != file))
  371.         {
  372.             InvertRect(&gRectToInvert);
  373.             SetRect(&gRectToInvert,(rank-1) << 5,(file-1) << 5,rank << 5,file << 5);
  374.             InvertRect(&gRectToInvert);
  375.             oldHiliteRank = rank;
  376.             oldHiliteFile = file;
  377.         }
  378.     }
  379.     else
  380.     {
  381.         SetCursor(&gChessCursor);
  382.         InvertRect(&gRectToInvert);
  383.         SetRect(&gRectToInvert,0,0,0,0);
  384.     }
  385. }
  386.  
  387. Boolean    CChessBoard::CheckForCheck(short secondClickRank, short secondClickFile)
  388. {
  389.     Boolean    check = false;
  390.     short    testFile,testRank,
  391.             savedFirstClickRank = firstClickRank,
  392.             savedFirstClickFile = firstClickFile;
  393.     CChessPiece    *testPiece,*savedPiece;
  394.     short        testPieceColor;
  395.  
  396.     savedPiece = theBoard[secondClickRank][secondClickFile];
  397.     theBoard[secondClickRank][secondClickFile] = theBoard[firstClickRank][firstClickFile];
  398.     theBoard[firstClickRank][firstClickFile] = NULL;
  399.  
  400.     // swap colors on virtual board to think like opponent
  401.     theOtherPlayersColor = myColor;
  402.     myColor = (myColor == White) ? Black : White;
  403.  
  404.     for(testFile=1;testFile<=8;testFile++)
  405.         for(testRank=1;testRank<=8;testRank++) 
  406.         {
  407.             testPiece = theBoard[testRank][testFile];
  408.             testPieceColor = (testPiece) ? testPiece->itsColor : NoColor;
  409.  
  410.             if (testPieceColor == myColor)
  411.             {
  412.                 register short    secondTestRank, secondTestFile;
  413.                 CChessPiece        *targetPiece;
  414.                 short            targetPieceColor;
  415.  
  416.                 firstClickRank = testRank;
  417.                 firstClickFile = testFile;
  418.         
  419.                 for(secondTestFile=1;secondTestFile<=8;secondTestFile++)
  420.                     for(secondTestRank=1;secondTestRank<=8;secondTestRank++)
  421.                     {
  422.                         targetPiece = theBoard[secondTestRank][secondTestFile];
  423.                         if (!targetPiece)
  424.                             continue;
  425.  
  426.                         targetPieceColor = targetPiece->itsColor;
  427.  
  428.                         if ((targetPieceColor == theOtherPlayersColor) &&
  429.                             !((testRank == secondTestRank) && (testFile == secondTestFile)) &&
  430.                             (testPiece->IsValidMove(this,secondTestRank,secondTestFile)))
  431.                         {
  432.                             if (targetPiece->itsValue == kKingValue)
  433.                             {
  434.                                 check = true;
  435.                                 goto EXIT;
  436.                             }
  437.                         }
  438.                     }
  439.             }
  440.         }
  441.  
  442. EXIT:
  443.     theOtherPlayersColor = myColor;
  444.     myColor = (myColor == White) ? Black : White;
  445.  
  446.     firstClickRank = savedFirstClickRank;
  447.     firstClickFile = savedFirstClickFile;
  448.     
  449.     theBoard[firstClickRank][firstClickFile] = theBoard[secondClickRank][secondClickFile];
  450.     theBoard[secondClickRank][secondClickFile] = savedPiece;
  451.     
  452.     return check;
  453. }